package pl.edu.utp.ga;

import java.util.ArrayList;

import pl.edu.utp.calculations.PopulationRate;
import pl.edu.utp.calculations.Range;
import pl.edu.utp.ga.genotypes.BinaryGenotype;
import pl.edu.utp.ga.genotypes.NumberGenotype;
import pl.edu.utp.ga.interfaces.Calculation;
import pl.edu.utp.ga.interfaces.Genotype;

public class Population{
	
	private static final int DEFAULT_POPULATION_SIZE = 100;
	private int size;
	private ArrayList<Individual> individuals;
	private int number;
	private double rate;
	private Class<? extends Genotype> genotypeClass = BinaryGenotype.class;
	
	public Population(int number){
		this(DEFAULT_POPULATION_SIZE, number);
	}
	
	public Population(int number, boolean generate){
		this(DEFAULT_POPULATION_SIZE, number, generate);
	}
	
	public Population(int size, int number, boolean generate){
		this(size, number);
		if(generate)
			generateIndividuals();
	}
	
	public Population(int size, int number){
		this.size = size;
		this.number = number;
		individuals = new ArrayList<Individual>(size);
	}
	
	public Population(ArrayList<Individual> individuals, int number){
		this.individuals = individuals;
		this.number = number;
		updateSize();
	}
	
	public void generateIndividuals(){
		for(int i=0;i<size;i++){
			Genotype genotype = null;
			if("BinaryGenotype".equals(genotypeClass.getSimpleName())){
				genotype = new BinaryGenotype();
			}else if("NumberGenotype".equals(genotypeClass.getSimpleName())){
				genotype = new NumberGenotype();
			}
			Individual individual = new Individual(this, genotype);
			individuals.add(individual);
		}
		updateSize();
	}
	
	public void generateIndividualsWithGenesRanges(ArrayList<Range> ranges){
		generateIndividuals();
		for(Individual individual: individuals){
			individual.generateWithGenesRanges(ranges);
		}
	}
	
	public int getSize(){
		return size;
	}
	
	public void rate(Calculation calculation){
		PopulationRate pRate = new PopulationRate(this);
		rate = pRate.rate(calculation);
	}
	
	public double getRate() {
		return rate;
	}

	public int getNumber() {
		return number;
	}

	public void addIndividual(Individual individual){
		individual.setPopulation(this);
		individuals.add(individual);
		updateSize();
	}
	
	public void removeIndividual(Individual individual){
		individuals.remove(individual);
		updateSize();
	}
	
	public Individual getIndividual(int position){
		return individuals.get(position);
	}
	
	public void clearIndividuals(){
		individuals.clear();
		updateSize();
	}
	
	public void setGenotypeClass(Class<? extends Genotype> genotypeClass){
		this.genotypeClass = genotypeClass;
	}
	
	public ArrayList<Individual> getIndividuals(){
		return individuals;
	}
	
	public String toString(){
		return String.format("no. %d Size: %d Rate: %.6f", number,size,rate);
	}
	
	private void updateSize(){
		this.size = individuals.size();
	}
}
